package com.letoken.platform.pub.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;


/**
 * @Date 2018/10/11 14:21
 * @Created GG
 * @Description 业务通用时间工具
 *
 */
public class LocalDateTool {
    /**
     * java1.8 的新特性，解决SimpleDateFormat的线程问题<br>
     * <li>Instant代替 Date，</li>
     * <li>LocalDateTime代替 Calendar，</li>
     * <li>DateTimeFormatter 代替 SimpleDateFormat.</li> 注意：如果是共享变量，则可能会出现线程问题。<br>
     * @author zero 2019/03/30
     */

    private static final String YEAR = "year";
    private static final String MONTH = "month";
    private static final String WEEK = "week";
    private static final String DAY = "day";
    private static final String HOUR = "hour";
    private static final String MINUTE = "minute";
    private static final String SECOND = "second";

    public static final DateTimeFormatter yyyyMM = DateTimeFormatter.ofPattern("yyyy-MM");
    public static final DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final DateTimeFormatter yyyyMMddHH = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
    public static final DateTimeFormatter yyyyMMddHHmm = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    public static final DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter HHmmss = DateTimeFormatter.ofPattern("HH:mm:ss");
    public static final DateTimeFormatter yyyyMMdd_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    public static final DateTimeFormatter yyyyMMddHH_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时");
    public static final DateTimeFormatter yyyyMMddHHmm_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分");
    public static final DateTimeFormatter yyyyMMddHHmmss_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒");
    public static final DateTimeFormatter HHmmss_CN = DateTimeFormatter.ofPattern("HH时mm分ss秒");

    public static final DateTimeFormatter SHOT_DATE = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
    public static final DateTimeFormatter FULL_DATE = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
    public static final DateTimeFormatter LONG_DATE = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
    public static final DateTimeFormatter MEDIUM_DATE = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);

    /**
     * 返回可选格式时间
     * @param dtf
     * @return
     */
    public static String getDefaultTime(DateTimeFormatter dtf){
        return LocalDateTime.now().format(dtf);
    }

    /**
     * 获取date的前后天数时间 的零点
     * @param date
     * @param n
     * @return
     */
    public static String plusDay(Date date,Integer n){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        localDateTime = localDateTime.plus(n, ChronoUnit.DAYS);
        return localDateTime.toLocalDate().atStartOfDay().format(yyyyMMddHHmmss);
    }

    public static LocalDateTime strToLocalDateTime(String s , DateTimeFormatter dtf){
        LocalDateTime localDateTime = LocalDateTime.parse(s,dtf);

        return localDateTime;
    }

    public static LocalDate strToLocalDate(String s ){
        LocalDate localDateTime = LocalDate.parse(s,yyyyMMdd);
        return localDateTime;
    }


    public static LocalDateTime plusYear(Date date,Integer n){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        localDateTime = localDateTime.plus(n, ChronoUnit.YEARS);
        return localDateTime;
    }

    public static LocalDateTime plusMonth(Date date,Integer n){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        localDateTime = localDateTime.plus(n, ChronoUnit.MONTHS);
        return localDateTime;
    }





    // 当前时间 + n 秒
    public static Date plusSeconds(Integer n){
        LocalDateTime localDateTime = LocalDateTime.now();
        localDateTime = localDateTime.plus(n, ChronoUnit.SECONDS);
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return  Date.from(zdt.toInstant());
    }




    // 前后天0点
    public static Date getDatePlusDay(Date date,Integer n){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        localDateTime = localDateTime.plus(n, ChronoUnit.DAYS);
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate localDate = localDateTime.toLocalDate();
        ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
        return Date.from(zdt.toInstant());
    }

    public static LocalDateTime plusDay(LocalDateTime localDateTime,Integer n){
        localDateTime = localDateTime.plus(n, ChronoUnit.DAYS);
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate localDate = localDateTime.toLocalDate();
        ZonedDateTime zdt = localDate.atStartOfDay(zoneId);
        return LocalDateTime.from(zdt.toLocalDateTime());
    }

    // 不是零点
    public static LocalDateTime plusDayFull(LocalDateTime localDateTime,Integer n){
        localDateTime = localDateTime.plus(n, ChronoUnit.DAYS);
        return localDateTime;
    }



    // date 前后整天的时间点
    public static Date getPreciseDatePlusDay(Date date,Integer n){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        localDateTime = localDateTime.plus(n, ChronoUnit.DAYS);
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }


    /**
     * 获取date的前后天数时间 日期
     * @param date
     * @param n
     * @return
     */
    public static String plusDayOfDay(Date date,Integer n){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        localDateTime = localDateTime.plus(n, ChronoUnit.DAYS);
        return localDateTime.toLocalDate().atStartOfDay().format(yyyyMMdd);
    }


    public static String getDefaultTime(Date date , DateTimeFormatter dtf){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.format(dtf);
    }



    public static Date getDefaultTimeTimeZone(Date date ){
        TimeZone newYorkTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
        DateFormat newYorkDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        newYorkDateFormat.setTimeZone(newYorkTimeZone);
        return   strToDateFull(newYorkDateFormat.format(date),yyyyMMddHHmmss);

    }








    public static String getZeroPoint(Date date){
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalDate().atStartOfDay().format(yyyyMMddHHmmss);


    }



    /* 字符串转Date 零点 */
    public static Date strToDateFull(String str,DateTimeFormatter formatter){
        LocalDateTime localDateTime = LocalDateTime.parse(str,formatter);
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
        Instant instant = zonedDateTime.toInstant();
        Date date = Date.from(instant);
        return date;
    }


    /* 字符串转Date 零点 */
    public static Date strToDate(String str,DateTimeFormatter formatter){

        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate localDate = LocalDate.parse(str,formatter);
        ZonedDateTime zdt = localDate.atStartOfDay(zoneId);

        return Date.from(zdt.toInstant());
    }



    /**
     * 通用返回格式时间
     * @param formatStr
     * @return
     */
    public static String getTime(String formatStr) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(formatStr));
    }


    /**
     * 根据yyyy-MM 获取该月的 第n天0点
     * @param text yyyy-MM格式时间
     * @param n 第几天
     * @return yyy-MM-dd 00:00:00
     */
    public static String getTimeByMonth(String text,Integer n){
        DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("yyyy-MM").parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter();
        LocalDate ld = LocalDate.parse(text, dtf);
        if (n == -1){
            n = ld.lengthOfMonth();
        }
        ld = ld.withDayOfMonth(n);
        return ld.atStartOfDay().format(yyyyMMddHHmmss);
    }

    /**
     * 获取当前月的第n天   n>=1  n=-1表示最后一天
     * @param n
     * @return
     */
    public static String getNowByMonth(Integer n){
        LocalDate ld = LocalDate.now();
        if (n == -1){
           n = ld.lengthOfMonth();
        }
        ld = ld.withDayOfMonth(n);
        return ld.atStartOfDay().format(yyyyMMdd);
    }


    /**
     * 获取当指定月的第n天   n>=1  n=-1表示最后一天  得到yyyy-MM-dd
     * @param n
     * @return
     */
    public static String getByMonth(String text,Integer n){
        DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("yyyy-MM").parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter();
        LocalDate ld = LocalDate.parse(text, dtf);
        if (n == -1){
            n = ld.lengthOfMonth();
        }
        ld = ld.withDayOfMonth(n);
        return ld.atStartOfDay().format(yyyyMMdd);
    }


    /**
     * yyyy-MM-dd HH:mm:ss 时间后一个月
     * @return
     */
    public static String plusMonth(String ds, Integer n){
        return LocalDateTime.parse(ds,yyyyMMddHHmmss).plusMonths(n).format(yyyyMMddHHmmss);
    }

    public static String plusMonthToDay(String ds, Integer n){
        return LocalDate.parse(ds,yyyyMMdd).plusMonths(n).format(yyyyMMdd);
    }



    /**
     * 获取d1比d2早的天数
     */
    public static long getDiff(Date d1, Date d2) {
        long time1 = d1.getTime();
        long time2 = d2.getTime();
        long between_days = (time1 - time2) / (1000 * 3600 * 24);

        return between_days;
    }


    /**
     * d1比d2多的小时
     * @param d1
     * @param d2
     * @return
     */
    public static long getDiffToHour(Date d1, Date d2) {
        long time1 = d1.getTime();
        long time2 = d2.getTime();
        long between_days = (time1 - time2) / (1000 * 3600);

        return between_days;
    }


    // d1 > d2
    public static long getDiffBySeconds(Date d1, Date d2) {
        long time1 = d1.getTime();
        long time2 = d2.getTime();
        long between_days = (time1 - time2) / 1000;

        return between_days;
    }

    /**
     * 当前时间truncate date ,然后叠加指定数量date
     * @return  日期
     */
    public static Date addDateTruncate(int date) {
        Calendar now = Calendar.getInstance();
        Date newDate = DateUtils.addDays(DateUtils.truncate(now, Calendar.DATE).getTime(), 1);
        return newDate;
    }



    /**
     *  获取t周的周一日期
     * @param t 0表示本周 -1表示上周 1表示下周
     * @param isFirst true 表示获取周一日期  false表示获取周日日期
     * @return
     */
    public static String getWeekDate(int t,Boolean isFirst){
        LocalDate local = LocalDate.now();
        LocalDate needDay;
        if (isFirst)
           needDay = local.plusDays(t*7-local.getDayOfWeek().getValue()+1);
        else {
            needDay = local.plusDays((t+1)*7 - local.getDayOfWeek().getValue());
        }
        return needDay.format(yyyyMMdd);
    }






    public  static  int getAge(String birthDay)  {
        birthDay = birthDay.substring(0,4) + "-" + birthDay.substring(4,6) + "-" + birthDay.substring(6,8);
        synchronized (LocalDateTool.class) {
            int age = 0;   //计算整岁数
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                Date birthDayAge = sdf.parse(birthDay);
                Calendar cal = Calendar.getInstance();
                if (cal.before(birthDayAge)) { //出生日期晚于当前时间，无法计算
                    return age;
                }
                int yearNow = cal.get(Calendar.YEAR);  //当前年份
                int monthNow = cal.get(Calendar.MONTH);  //当前月份
                int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
                cal.setTime(birthDayAge);
                int yearBirth = cal.get(Calendar.YEAR);
                int monthBirth = cal.get(Calendar.MONTH);
                int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
                age = yearNow - yearBirth;
                if (monthNow <= monthBirth) {
                    if (monthNow == monthBirth) {
                        if (dayOfMonthNow < dayOfMonthBirth) {
                            age--;//当前日期在生日之前，年龄减一
                        }
                    } else {
                        age--;//当前月份在生日之前，年龄减一
                    }
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return age;
        }
    }


    // 后面的比前面的大 返回正数
    public static Integer calculateHourDiff(String startTime,String endTime) {

        try {
            SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            long from = simpleFormat.parse(startTime).getTime();
            long to = simpleFormat.parse(endTime).getTime();
            Integer hours = (int) ((to - from)/(1000 * 60 * 60*1.0));
            return hours;
        }catch (Exception e) {
            e.printStackTrace();
            return 0;
        }

    }

    public static long getDiffByDate(String start,String end){
        LocalDate startDate = strToLocalDate(start);
        LocalDate endDate = strToLocalDate(end);
        long daysDiff = startDate.until(endDate, ChronoUnit.DAYS);
        return daysDiff;
    }


    public static void main(String[] args) {
        LocalDateTime d1 = strToLocalDateTime("2023-11-03 00:12:34",yyyyMMddHHmmss);
        LocalDateTime d2 = strToLocalDateTime("2023-11-06 00:01:34",yyyyMMddHHmmss);


        System.out.printf("" + getDiffByDate("2023-11-03","2023-11-06"));
    }
}



 